/**
 * @author Tobias Boehm
 *
 * 19.04.2011
 */
package org.anddev.andengine.extension.tbsengine.menu.activity;

import java.util.List;

import org.anddev.andengine.extension.tbsengine.map.AbsMapOverview;
import org.anddev.andengine.extension.tbsengine.menu.view.IChooseMapView;
import org.anddev.andengine.extension.tbsengine.shared.MatchJoinOrPreparationType;
import org.anddev.andengine.extension.tbsengine.shared.NoMatchPreparationTypeProvidedException;
import org.anddev.andengine.extension.tbsengine.shared.TBSengineConstants;

import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;

/**
 * This is an abstract implementation of an activity for map choosing.
 * <p>
 * Notice:<br>
 * If you try to start an activity which extends this class, make sure you 
 * provide a valid name of a {@link MatchJoinOrPreparationType} as Intent Extra.
 * The flag is {@link TBSengineConstants#TBSE_MATCH_JOIN_OR_PREPARATION_TYPE_INTENT_EXTRA}.
 * 
 * 
 * @author Tobias Boehm
 *
 * @param <MapOverviewClass> - Your implementation of {@link AbsMapOverview}
 * @param <ChooseMapViewClass> - Your view for this activity which implements {@link IChooseMapView}
 */
public abstract class AbsChooseMapActivity<MapOverviewClass extends AbsMapOverview,
										   ChooseMapViewClass extends View & IChooseMapView<MapOverviewClass>>

										   extends AbsFullscreenActivity implements TBSengineConstants {

	/**
	 * The match preparation type which was used to start this part of the match
	 * preparation process.
	 */
	protected MatchJoinOrPreparationType mMatchPreparationType;
	
	/**
	 * The view of this activity.
	 */
	protected ChooseMapViewClass mChooseMapView;
	
	/**
	 * The instance of your implementation of {@link AbsMapOverview} which was
	 * chosen by the user.
	 */
	protected MapOverviewClass mChoosenMapOverview;
	
	/**
	 * An asynchronous task which handles the map overview's loading. It informs
	 * the view about the begin and the end of the loading process and executes
	 * your implementation of {@link #loadMapOverviewsList(MatchJoinOrPreparationType)}.
	 */
	protected final AsyncTask<MatchJoinOrPreparationType, Void, List<MapOverviewClass>> mAsyncMapListLoader = new AsyncTask<MatchJoinOrPreparationType, Void, List<MapOverviewClass>>(){

		protected void onPreExecute() {
			
			mChooseMapView.onStartLoadingMapOverviewList();
		};
		
		@Override
		protected List<MapOverviewClass> doInBackground(MatchJoinOrPreparationType... params) {
			
			final List<MapOverviewClass> mapList = loadMapOverviewsList(params[0]);
			
			return mapList;
		}
		
		protected void onPostExecute(List<MapOverviewClass> result) {
			
			mChooseMapView.fillMapOverviewsList(result);
		};
	};
	
	/**
	 * This method should return a list of all map overviews you want to present
	 * to the player. You can use the given match preparation type to decide
	 * which maps you want to present. (exclude singleplayer-only maps for example)
	 * 
	 * @param pMatchPreparationType - The match preparation type used to start 
	 * this part of the match preparation process.
	 * 
	 * @return a list of instances of your implementation of {@link AbsMapOverview} you want to present to the player.
	 */
	protected abstract List<MapOverviewClass> loadMapOverviewsList(final MatchJoinOrPreparationType pMatchPreparationType);
	
	/**
	 * This method should return a view which implements {@link IChooseMapView}.
	 * The view gets set as main view for this activity.
	 * 
	 * @return - A  view which implements {@link IChooseMapView}.
	 */
	protected abstract ChooseMapViewClass createChooseMapView();
	
	
	/**
	 * This method should return the .class of your implementation of {@link AbsPrepareMatchActivity}.
	 * Make sure you registered the class in you AndroidManifest.xml!
	 * 
	 * @return the .class of your implementation of {@link AbsPrepareMatchActivity}
	 */
	protected abstract Class<? extends AbsPrepareMatchActivity> getPrepareMatchActivityClass();
	
	/**
	 * You should call this method from your controller if the user has chosen a
	 * map overview object. It saves the choice and informs the view as well.
	 * 
	 * @param pChosenMapOverview - The chosen map overview.
	 */
	public void setChosenMap(final MapOverviewClass pChosenMapOverview){
	
		this.mChoosenMapOverview = pChosenMapOverview;
		
		this.mChooseMapView.setChosenMapOverview(pChosenMapOverview);
	}
	
	/**
	 * You should call this method to start the match preparation activity.
	 * The method check if a map got chosen and puts the map ID and the
	 * match preparation type as "Extra" into the Intent. Afterwards it starts
	 * the activity.
	 */
	public void startMatchPreparation() {
		
		if(this.mChoosenMapOverview == null){
		
			throw new IllegalStateException("You have to setChoosenMap() first.");
			
		}else{
			
			final Intent intent = new Intent(this, this.getPrepareMatchActivityClass());
								
			intent.putExtra(TBSE_MATCH_JOIN_OR_PREPARATION_TYPE_INTENT_EXTRA, this.mMatchPreparationType.name());
			
			intent.putExtra(TBSE_MAP_ID_INTENT_EXTRA, mChoosenMapOverview.getMapID());
			
			this.startActivity(intent);
		}	
	}
			
	@Override
	protected void onDestroy() {
		super.onDestroy();
		
		if(this.mAsyncMapListLoader != null){
			
			this.mAsyncMapListLoader.cancel(true);
		}
	}
	
	/**
	 * This activity expects that you provide a valid name of a {@link MatchJoinOrPreparationType} as Intent Extra.
	 * The flag is {@link TBSengineConstants#TBSE_MATCH_JOIN_OR_PREPARATION_TYPE_INTENT_EXTRA}.
	 * 
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		try {
			this.mMatchPreparationType = MatchJoinOrPreparationType.valueOf(getIntent().getStringExtra(TBSE_MATCH_JOIN_OR_PREPARATION_TYPE_INTENT_EXTRA));
			
			this.mChooseMapView = createChooseMapView();
			
			this.setContentView(this.mChooseMapView);
			
			this.mAsyncMapListLoader.execute(this.mMatchPreparationType);
			
		} catch (Exception e) {
				
			throw new NoMatchPreparationTypeProvidedException();
		}
	}
}